<template>
  <!-- 搜索区域 -->
  <ContentWrap>
    <el-form
      class="-mb-15px"
      :model="queryParams"
      ref="queryFormRef"
      :inline="true"
      label-width="80px"
    >
      <el-form-item label="流程分类" :class="{ 'w-full': categoryList?.length > 5 }">
        <div class="flex gap-3">
          <el-tag
            v-for="category in categoryList"
            :key="category.code"
            :effect="queryParams.category == category.code ? 'dark' : 'plain'"
            @click="handleCategoryClick(category)"
            class="min-w-50px"
            style="cursor: pointer"
          >
            {{ category.name }}
          </el-tag>
        </div>
        <!--        <el-select-->
        <!--          v-model="queryParams.category"-->
        <!--          @change="handleCategoryChange"-->
        <!--          placeholder="请选择分类"-->
        <!--          clearable-->
        <!--          class="!w-240px"-->
        <!--        >-->
        <!--          <el-option-->
        <!--            v-for="category in categoryList"-->
        <!--            :key="category.code"-->
        <!--            :label="category.name"-->
        <!--            :value="category.code"-->
        <!--          />-->
        <!--        </el-select>-->
      </el-form-item>
      <el-form-item label="流程标识" prop="key">
        <el-input
          v-model="queryParams.key"
          placeholder="请输入流程标识"
          clearable
          @keyup.enter="handleQuery"
          class="!w-240px"
        />
      </el-form-item>
      <el-form-item label="流程名称" prop="name">
        <el-input
          v-model="queryParams.name"
          placeholder="请输入流程名称"
          clearable
          @keyup.enter="handleQuery"
          class="!w-240px"
        />
      </el-form-item>
      <el-form-item>
        <el-button @click="handleQuery">
          <Icon icon="ep:search" class="mr-5px" />
          搜索
        </el-button>
        <el-button @click="resetQuery">
          <Icon icon="ep:refresh" class="mr-5px" />
          重置
        </el-button>
        <el-button
          type="primary"
          plain
          @click="openForm('create')"
          v-hasPermi="['bpm:model:create']"
        >
          <Icon icon="ep:plus" class="mr-5px" />
          新增
        </el-button>
      </el-form-item>
    </el-form>
  </ContentWrap>

  <!-- 列表区域 -->
  <ContentWrap>
    <el-table
      ref="tableRef"
      v-loading="listLoading"
      :data="list"
      row-key="id"
      :stripe="true"
      :show-overflow-tooltip="true"
    >
      <el-table-column label="流程名称" prop="name" width="250">
        <template #default="{ row }">
          <div class="flex items-center">
            <Icon
              v-if="isModelSorting"
              icon="ic:round-drag-indicator"
              class="drag-icon cursor-move text-#8a909c mr-10px"
            />
            <el-image
              v-if="row.icon"
              :src="s_file_url(row.icon)"
              class="h-38px w-38px mr-10px rounded"
            />
            <div v-else class="flow-icon">
              <span style="font-size: 12px; color: #fff">{{ subString(row.name, 0, 2) }}</span>
            </div>
            {{ row.name }}
          </div>
        </template>
      </el-table-column>
      <el-table-column label="流程标识" prop="key" width="200" />
      <el-table-column label="是否可见" prop="visible" width="120">
        <template #default="{ row }">
          <dict-tag :options="common_bool_type" :value="row.visible" />
        </template>
      </el-table-column>
      <el-table-column label="发起权限" prop="startUserIds" width="200">
        <template #default="{ row }">
          <el-text v-if="!row.startUsers?.length"> 全员</el-text>
          <el-text v-else-if="row.startUsers.length === 1">
            {{ row.startUsers[0].nickname }}
          </el-text>
          <el-text v-else>
            <el-tooltip
              class="box-item"
              effect="dark"
              placement="top"
              :content="row.startUsers.map((user: any) => user.nickname).join('、')"
            >
              {{ row.startUsers[0].nickname }}等 {{ row.startUsers.length }} 人可发起
            </el-tooltip>
          </el-text>
        </template>
      </el-table-column>
      <el-table-column label="流程分类" prop="categoryName" width="130" />
      <el-table-column label="发起表单" prop="formType" width="190">
        <template #default="scope">
          <el-button
            v-if="scope.row.formType === BpmModelFormTypeEnum.Normal"
            type="primary"
            link
            @click="previewStartForm(scope.row)"
          >
            <span>{{ scope.row.formName }}</span>
          </el-button>
          <el-button
            v-else-if="scope.row.formType === BpmModelFormTypeEnum.Custom"
            type="primary"
            link
            @click="previewStartForm(scope.row)"
          >
            <span>{{ scope.row.formCustomCreatePath }}</span>
          </el-button>
          <label v-else>暂无表单</label>
        </template>
      </el-table-column>
      <el-table-column label="最后发布" prop="deploymentTime" min-width="250">
        <template #default="scope">
          <div class="flex items-center">
            <span v-if="scope.row.processDefinition" class="w-150px">
              {{ scope.row.processDefinition.deploymentTime }}
            </span>
            <el-tag disable-transitions v-if="scope.row.processDefinition">
              v{{ scope.row.processDefinition.version }}
            </el-tag>
            <el-tag v-else disable-transitions type="warning">未部署</el-tag>
            <el-tag
              v-if="scope.row.processDefinition?.suspended"
              disable-transitions
              type="warning"
              class="ml-10px"
            >
              已停用
            </el-tag>
          </div>
        </template>
      </el-table-column>
      <!--      <el-table-column label="创建时间" prop="createTime" width="180" />-->
      <el-table-column width="240" fixed="right">
        <template #header>
          <div style="display: flex; justify-content: space-between; align-items: center">
            <span>操作</span>
            <template v-if="hasPermi('bpm:model:sort') && !hasQueryCondition">
              <div v-if="!isModelSorting">
                <el-button link type="info" class="mr-10px" @click.stop="handleModelSort">
                  <Icon icon="fa:sort-amount-desc" class="mr-3px" />
                  排序
                </el-button>
              </div>
              <div v-else>
                <el-button link @click.stop="handleModelSortCancel">取消</el-button>
                <el-button type="primary" link @click.stop="handleModelSortSubmit"
                  >保存排序
                </el-button>
              </div>
            </template>
          </div>
        </template>
        <template #default="scope">
          <el-button
            link
            type="primary"
            @click="openForm('update', scope.row.id)"
            v-if="hasPermiUpdate"
            :disabled="!isManagerUser(scope.row)"
          >
            编辑
          </el-button>
          <el-button
            link
            type="primary"
            @click="openForm('copy', scope.row.id)"
            v-if="hasPermiCreate"
            :disabled="!isManagerUser(scope.row)"
          >
            复制
          </el-button>
          <el-button
            link
            type="primary"
            @click="handleDeploy(scope.row)"
            v-if="hasPermiDeploy"
            :disabled="!isManagerUser(scope.row)"
          >
            发布
          </el-button>
          <el-dropdown
            class="!align-middle ml-5px"
            @command="(command) => handleModelCommand(command, scope.row)"
            v-if="hasPermiMore"
          >
            <el-button type="primary" link>更多</el-button>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item
                  command="handleDefinitionList"
                  v-if="hasPermiPdQuery"
                  :disabled="!isManagerUser(scope.row)"
                >
                  历史
                </el-dropdown-item>
                <el-dropdown-item
                  command="handleReport"
                  v-if="hasPermiPiQuery && scope.row.processDefinition"
                  :disabled="!isManagerUser(scope.row)"
                >
                  报表
                </el-dropdown-item>
                <el-dropdown-item
                  command="handleChangeStatus"
                  v-if="hasPermiUpdate && scope.row.processDefinition"
                  :disabled="!isManagerUser(scope.row)"
                >
                  {{ scope.row.processDefinition.suspended ? '启用' : '停用' }}
                </el-dropdown-item>
                <el-dropdown-item
                  type="danger"
                  command="handleClean"
                  v-if="hasPermiClean"
                  :disabled="!isManagerUser(scope.row)"
                >
                  清理
                </el-dropdown-item>
                <el-dropdown-item
                  type="danger"
                  command="handleDelete"
                  v-if="hasPermiDelete"
                  :disabled="!isManagerUser(scope.row)"
                >
                  删除
                </el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页区域 -->
    <Pagination
      :total="total"
      v-model:page="queryParams.pageNo"
      v-model:limit="queryParams.pageSize"
      @pagination="getList"
    />
  </ContentWrap>

  <!-- 弹窗：表单详情 -->
  <Dialog title="表单详情" v-model="formPreviewVisible">
    <form-create :rule="formPreview.rule" :option="formPreview.option" />
  </Dialog>
</template>

<script setup lang="ts">
import { ModelApi, ModelVO } from '@/api/bpm/model'
import { CategoryApi, CategoryVO } from '@/api/bpm/category'
import { FormApi, FormVO } from '@/api/bpm/form'
import { setFormConfAndFields } from '@/utils/formCreate'
import { useUserStore } from '@/stores/modules/user'
import { DICT_TYPE } from '@/utils/dict'
import { BpmModelFormTypeEnum, BpmModelStatusEnum } from '@/utils/constants'
import { hasAnyPermi, hasPermi, isAdmin } from '@/utils/perm'
import { s_file_url, subString } from '@/utils/lizard'
import Sortable from 'sortablejs'
import { cloneDeep } from 'lodash-es'
import { useDebounceFn } from '@vueuse/core'

defineOptions({ name: 'BpmModel' })

const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
const route = useRoute()
const { push } = useRouter() // 路由
const userStore = useUserStore()
const { common_bool_type } = useBoolDict(DICT_TYPE.common_bool_type)

const listLoading = ref(true) // 列表的加载中状态
const list = ref<ModelVO[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数
const queryParams = reactive({
  category: '',
  key: undefined,
  name: undefined,
  pageNo: 1,
  pageSize: 20
})
const queryFormRef = ref() // 搜索的表单
const categoryList = ref<CategoryVO[]>([])

// 是否有查询条件
const queriedParams = reactive({ ...queryParams })
const hasQueryCondition = computed(() => {
  return Object.entries(queriedParams).some(([key, value]) => {
    if (['category', 'pageNo', 'pageSize'].includes(key)) {
      return false
    }
    return value !== undefined && value !== null && String(value).trim() !== ''
  })
})

/** 查询列表 */
const getList = async () => {
  listLoading.value = true
  try {
    isModelSorting.value = false
    disableModelSort()
    const data = await ModelApi.getModelPage(queryParams)
    list.value = data.content
    total.value = data.totalElement
    Object.assign(queriedParams, queryParams)
  } finally {
    listLoading.value = false
  }
}

/** 搜索按钮操作 */
const handleQuery = () => {
  queryParams.pageNo = 1
  getList()
}

/** 重置按钮操作 */
const resetQuery = () => {
  queryFormRef.value.resetFields()
  handleQuery()
}

/** 添加/修改操作 */
const openForm = (type: string, id?: string) => {
  // 使用路由名称的方式，以便后续可以方便调整路由的path
  if (type === 'create') {
    push({ name: 'BpmModelCreate', state: { category: queryParams.category } })
  } else {
    push({ name: 'BpmModelUpdate', params: { type, id } })
  }
}

const handleModelCommand = (command: string, model: ModelVO) => {
  switch (command) {
    case 'handleDefinitionList':
      handleDefinitionList(model)
      break
    case 'handleDelete':
      handleDelete(model)
      break
    case 'handleChangeStatus':
      handleChangeStatus(model)
      break
    case 'handleClean':
      handleClean(model)
      break
    case 'handleReport':
      push({
        name: 'BpmProcessInstanceReport',
        query: {
          processDefinitionId: model.processDefinition.id,
          processDefinitionKey: model.key
        }
      })
      break
  }
}

/** 查看发布历史 */
const handleDefinitionList = (model: ModelVO) => {
  push({
    name: 'BpmProcessDefinition',
    params: {
      key: model.key
    }
  })
}

/** 修改流程状态 */
const handleChangeStatus = async (model: ModelVO) => {
  const suspended = model.processDefinition.suspended
  const toStatus = suspended ? BpmModelStatusEnum.Active : BpmModelStatusEnum.Suspended
  try {
    const action = suspended ? '启用' : '停用'
    const content = '是否确认' + action + '名称为"' + model.name + '"的流程?'
    await message.confirm(content)
    await ModelApi.updateModelStatus(model.id, toStatus)
    message.success(action + '成功')
    // 刷新列表
    await getList()
  } catch {}
}

const handleDeploy = async (model: ModelVO) => {
  try {
    await message.confirm('是否确认发布该流程？')
    // 发起部署
    await ModelApi.deployModel(model.id)
    message.success(t('发布成功'))
    // 刷新列表
    await getList()
  } catch {}
}

/** 删除按钮操作 */
const handleDelete = async (model: ModelVO) => {
  try {
    // 弹出确认框
    await message.delConfirm('是否确认删除名称为"' + model.name + '"的流程?')
    // 发起删除请求
    await ModelApi.deleteModel(model.id)
    message.success(t('common.delSuccess'))
    // 刷新列表
    await getList()
  } catch {}
}

/** 清理按钮操作 */
const handleClean = async (model: ModelVO) => {
  try {
    // 清理的二次确认
    await message.confirm('是否确认清理名称为"' + model.name + '"的流程?')
    // 发起清理
    await ModelApi.cleanModel(model.id)
    message.success('清理成功')
    // 刷新列表
    await getList()
  } catch {}
}

/** 流程表单的详情按钮操作 */
const formPreviewVisible = ref(false)
const formPreview = ref({
  rule: [],
  option: {}
})
const previewStartForm = async (model: ModelVO) => {
  if (model.formType == BpmModelFormTypeEnum.Normal) {
    const data: FormVO = await FormApi.getForm(model.formId)
    setFormConfAndFields(formPreview, data.conf, data.fields, true)
    formPreviewVisible.value = true
  } else {
    await push({ path: model.formCustomCreatePath })
  }
}

// const handleCategoryChange = () => {
//   handleQuery()
// }

const handleCategoryClick = (category: CategoryVO) => {
  queryParams.category = category.code
  handleQuery()
}

const tableRef = ref()
const isModelSorting = ref(false) // 是否正处于排序状态
const originalData = ref<ModelVO[]>([]) // 原始数据，用于取消排序后的数据还原
let sortableInstance: Sortable | null = null // 保存 Sortable 实例引用

const handleModelSort = () => {
  originalData.value = cloneDeep(list.value)
  isModelSorting.value = true
  enableModelSort()
}

const handleModelSortCancel = async () => {
  // 还原排序前数据
  list.value = originalData.value
  isModelSorting.value = false
  disableModelSort()
}

const handleModelSortSubmit = async () => {
  if (!list.value?.length) return
  const ids = list.value.map((model: ModelVO) => model.id)
  await ModelApi.updateModelSortBatch(ids)
  message.success('模型排序成功')
  await getList()
}

const enableModelSort = useDebounceFn(() => {
  if (!tableRef.value) return
  const tableEl = tableRef.value.$el.querySelector('.el-table__body-wrapper tbody')
  if (!tableEl) return

  disableModelSort()

  sortableInstance = Sortable.create(tableEl, {
    animation: 150,
    draggable: '.el-table__row',
    handle: '.drag-icon',
    onEnd({ newDraggableIndex, oldDraggableIndex }) {
      list.value.splice(newDraggableIndex!, 0, list.value.splice(oldDraggableIndex!, 1)[0])
    }
  })
}, 200)

function disableModelSort() {
  if (sortableInstance) {
    sortableInstance.destroy()
    sortableInstance = null
  }
}

const _isAdmin = isAdmin()
const isManagerUser = (model: ModelVO) => {
  if (_isAdmin) {
    return true
  }
  const userId = userStore.getUser.userId
  return model.manageUserIds?.includes(userId)
}

/** 权限校验：通过 computed 解决列表的卡顿问题，computed会进行缓存 */
const hasPermiCreate = computed(() => {
  return hasAnyPermi(['bpm:model:create'])
})
const hasPermiUpdate = computed(() => {
  return hasAnyPermi(['bpm:model:update'])
})
const hasPermiDelete = computed(() => {
  return hasAnyPermi(['bpm:model:delete'])
})
const hasPermiClean = computed(() => {
  return hasAnyPermi(['bpm:model:clean'])
})
const hasPermiDeploy = computed(() => {
  return hasAnyPermi(['bpm:model:deploy'])
})
const hasPermiPdQuery = computed(() => {
  return hasAnyPermi(['bpm:process-definition:query'])
})
const hasPermiPiQuery = computed(() => {
  return hasAnyPermi(['bpm:process-instance:manage-query'])
})
const hasPermiMore = computed(() => {
  return hasPermiPdQuery || hasPermiUpdate || hasPermiClean || hasPermiDelete
})

/** 模型操作返回后，重新加载列表 */
const firstLoad = ref(true)
onActivated(() => {
  // keepalive组件才会启用，首次装载会在onMounted之后执行，后续从keepalive中被激活也会执行
  if (firstLoad.value) {
    // 确保不与onMounted重复执行逻辑
    firstLoad.value = false
    return
  }
  if (history.state?.reload) {
    getList()
  }
})

/** 初始化 **/
onMounted(async () => {
  categoryList.value = await CategoryApi.getCategorySimpleList()
  if (categoryList.value?.length) {
    queryParams.category = categoryList.value[0].code
  }
  await getList()
})

onUnmounted(() => {
  disableModelSort()
})
</script>

<style scoped lang="scss">
.flow-icon {
  display: flex;
  width: 38px;
  height: 38px;
  margin-right: 10px;
  background-color: var(--el-color-primary);
  border-radius: 0.25rem;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
</style>
